# -*- coding:utf-8 -*-
# @Time : 21-8-16 上午9:25 
# @Author : zdy
# @File : UILinearity.py
# desc:线性化校正，取偏差最小的线性化系数，（计算时，不考虑空白、多点校正的问题）
from UI.Linearity import Ui_Linearity
from Class.Devices import *
import pyqtgraph as pg
from pyqtgraph import PlotWidget
from Class.CSConfig import BaseCalibrationItem
from Class.VoltSignal import VoltSignal
from Class.Factor import Factor
from Class.LSFit import Fit
from importQT import *
class UILinearity(QDialog, Ui_Linearity):
    def __init__(self,baseitems,channel):
        super(UILinearity, self).__init__()
        self.setupUi(self)
        self.setWindowFlags(Qt.WindowCloseButtonHint)
        self.setFixedSize(self.width(), self.height())
        self.setWindowTitle('线性化')
        self.applyResource()
        self.items = baseitems
        self.currentChannel = channel
        self.dSpinBoxStepLinearity.setValue(device.config.factors[self.currentChannel].linearity)
        self.rr =[] #存放不同线性化值的残方差
        self.lin =[]    #存放尝试的各线性化值
        self.initGraph()
        self.btnCal.clicked.connect(self.btnCal_clicked)
        self.btnClose.clicked.connect(self.btnClose_clicked)
        self.btnOK.clicked.connect(self.btnOK_clicked)

    def applyResource(self):
        self.setWindowIcon(getIcon())

    def initGraph(self):
        # 进行全局设置：禁止拖动、前景色为黑色、背景色为白色；
        pg.setConfigOptions(leftButtonPan=False)
        pg.setConfigOption('background', 'w')
        pg.setConfigOption('foreground', 'k')
        pg.PlotItem().setMenuEnabled(False)
        self.graph = PlotWidget(self)
        self.gridLayout.addWidget(self.graph)
        self.graph.setLabel("left", "偏差")
        self.graph.setLabel("bottom", "线性化系数")

    def btnCal_clicked(self):
        '''根据步长，依次求取线性化面积，并拟合得到绝对质量，计算与标准值退出的绝对质量的方差，找到方差最小的'''
        if len(self.items) <2:
            QMessageBox.warning(self,"提示",'数据太少')
            return
        start = self.spinBoxStart.value()
        stop = self.spinBoxStop.value()
        step = self.dSpinBoxStep.value()
        areas = []
        standards =[]   #存放标准值对应的元素绝对含量
        newResults =[]
        vss = []    #存放所有实验数据信息
        for item in self.items:
            factor = Factor()
            if (item.include and bool(1-item.input)):
                vs = VoltSignal.loadAll(item.id)
                if vs == None:
                    QMessageBox.warning(self, "提示", "找不到数据")
                    return
                item.weight = vs.sampleWeight
                item.flux = vs.fluxWeight
                item.blank = vs.factors[self.currentChannel].blank
                vss.append(vs)
                #不考虑多点校正、空白、单点校正参数
                standards.append(factor.calculateElementWeightFromStandard(item.standard, item.weight, item.blank,
                                                                           item.flux))
        if len(vss) >0:
            self.rr.clear()
            self.lin.clear()
            times =int((stop - start)/step)
            for i in range(times):
                l = start + i*step
                areas.clear()
                newResults.clear()
                factor.linearity = l
                for vs in vss:
                    area = factor.calculateAreabyFactor(vs.listT,vs.listData[self.currentChannel],vs.average[self.currentChannel])
                    areas.append(area)
                params = Fit.LineFit(areas,standards,device.config.factors[self.currentChannel].orgin)
                k = params[0]
                b =params[1]
                for j in areas:
                    newResults.append(k*j + b)
                self.rr.append(self.calculateR(standards, newResults))
                self.lin.append(l)
            index =self.rr.index(min(self.rr))

            self.txtDeviation.setText("{:.{}f}".format(self.rr[index], 6))
            self.dSpinBoxStepLinearity.setValue(self.lin[index])
            self.graph.clear()
            self.graph.plot(x=self.lin, y=self.rr, pen=pg.mkPen(color="b", width=2))


    def calculateR(self,results:[], standards:[]):
        '''
        计算两个数组的系统残方差
        :param results:
        :param standards:
        :return:残方差
        '''
        rr = 0
        count =len(results)
        for i in range(count):
            rr +=abs((results[i] - standards[i]) **2)
        return rr

    def btnClose_clicked(self):
        self.close()

    def btnOK_clicked(self):
        device.config.factors[self.currentChannel].linearity = self.dSpinBoxStepLinearity.value()
        self.close()


